#include "xdecode.h"
#include "xdemux.h"
#include "xencode.h"
#include "xmux.h"
#include <cstring>
#include <iostream>

using namespace std;
extern "C" { // 指定函数是c语言函数，函数名不包含重载标注
// 引用ffmpeg头文件
#include <libavformat/avformat.h>
}
#ifdef main
#undef main
#endif // !main
int main(int argc, char *argv[]) {
  // 使用说明
  string useage = "124_test_xformat 输入文件 输出文件 <开始时间s <结束时间s>> "
                  "视频宽 视频高";
  useage += "\n例如：124_test_xformat 1080.mp4 10 20 400 300";
  cout << useage << endl;
  if (argc < 3) {
    return -1;
  }
  av_log_set_level(AV_LOG_ERROR);
  //////////////输入参数处理
  string in_file = argv[1];
  string out_file = argv[2];
  int begin_sec = 0; // 截取开始时间
  int end_sec = 0;   // 截取结束时间
  int n = 0;
  if (argc > 3) {
    begin_sec = std::atoi(argv[3]);
  }
  if (argc > 4) {
    end_sec = std::atoi(argv[4]);
  }
  int video_width = 0;
  int video_height = 0;
  if (argc > 5) {
    video_width = std::atoi(argv[5]);
    video_height = std::atoi(argv[6]);
  }
  // const char *url = "v1080.mp4";
  //////////////////////////////
  /// 解封装
  // 解封装输入上下文
  XDemux demux;
  auto demux_c = demux.Open(in_file.c_str());
  demux.set_c(demux_c);
  long long video_begin_pts = 0;
  long long video_end_pts = 0;
  long long audio_begin_pts = 0;
  // long long audio_end_pts = 0;
  //  算出输入
  if (begin_sec > 0) {
    auto time_base = demux.video_time_base();
    if (demux.video_index() >= 0 && time_base.num != 0) {
      double t = static_cast<double>(time_base.den) /
                 static_cast<double>(time_base.num);
      video_begin_pts = t * begin_sec;
      video_end_pts = t * end_sec;
      demux.Seek(video_begin_pts, demux.video_index());
    }
    time_base = demux.audio_time_base();
    if (demux.audio_index() >= 0 && time_base.num != 0) {
      double t = static_cast<double>(time_base.den) /
                 static_cast<double>(time_base.num);
      audio_begin_pts = t * begin_sec;
      // audio_end_pts = t * end_sec;
      // demux.Seek(audio_begin_pts, demux.audio_index());
    }
  }
  ////////////////////////////////////////////
  ///////////////////////////////////////////////
  /// 解码的初始化
  XDecode decode;
  auto decode_c = decode.Create(demux.video_codec_id(), false);
  // 设定视频解码器参数
  decode_c->thread_count = 8;
  demux.CopyPara(demux.video_index(), decode_c);
  decode.set_c(decode_c);
  decode.Open();
  AVFrame *frame = decode.CreateFrame();
  ///////////////////////////////////////////
  /// 视频编码的初始化
  if (demux.video_index() >= 0) {
    if (video_width <= 0)
      video_width = demux_c->streams[demux.video_index()]->codecpar->width;
    if (video_height <= 0)
      video_height = demux_c->streams[demux.video_index()]->codecpar->height;
  }
  XEncode encode;
  auto encode_c = encode.Create(AV_CODEC_ID_H265, true);
  encode_c->pix_fmt = AV_PIX_FMT_YUV420P;
  encode_c->width = video_width;
  encode_c->height = video_height;
  encode.set_c(encode_c);
  encode.Open();
  /////////////////////////////////////////
  ////////////////////////////////////////////////////////////////////////////////////
  /// 封装
  XMux mux;
  auto mux_c = mux.Open(out_file.c_str());
  mux.set_c(mux_c);
  auto mvs = mux_c->streams[mux.video_index()];
  auto mas = mux_c->streams[mux.audio_index()];
  // 有视频
  if (demux.video_index() >= 0) {
    mvs->time_base.num = demux.video_time_base().num;
    mvs->time_base.den = demux.video_time_base().den;
    // demux.CopyPara(demux.video_index(), mvs->codecpar);
    // 复制编码器格式
    avcodec_parameters_from_context(mvs->codecpar, encode_c);
  }
  // 有音频
  if (demux.audio_index() >= 0) {
    mas->time_base.num = demux.audio_time_base().num;
    mas->time_base.den = demux.audio_time_base().den;
    demux.CopyPara(demux.audio_index(), mas->codecpar);
  }
  // 写入头部，会改变timebase
  auto re = mux.WriteHeader();

  int audio_count = 0;
  int video_count = 0;
  double total_sec = 0.;
  AVPacket pkt;
  for (;;) {
    if (!demux.Read(&pkt)) {
      break;
    }
    if (video_begin_pts > 0 && pkt.stream_index == demux.video_index() &&
        pkt.pts > video_end_pts) {
      av_packet_unref(&pkt);
      break;
    }
    if (pkt.stream_index == demux.video_index()) {
      mux.RescaleTime(&pkt, video_begin_pts, demux.video_time_base());
      if (decode.Send(&pkt)) {
        while (decode.Receive(frame)) {
          // 修改图像尺寸
          // 视频编码
          auto epkt = encode.Encode(frame);
          if (epkt) {
            epkt->stream_index = mux.video_index();
            mux.Write(epkt); // 写入视频
            // av_packet_free(&epkt);
          }
        }
      }
      video_count++;
      if (demux.video_time_base().den > 0)
        total_sec += pkt.duration * (double(demux.video_time_base().num) /
                                     double(demux.video_time_base().den));

    } else if (pkt.stream_index == demux.audio_index()) {
      mux.RescaleTime(&pkt, audio_begin_pts, demux.audio_time_base());
      audio_count++;
      re = mux.Write(&pkt);
    } else
      av_packet_unref(&pkt);
  }
  mux.WriteEnd();
  demux.set_c(nullptr);
  mux.set_c(nullptr);
  decode.set_c(nullptr);
  encode.set_c(nullptr);
  cout << "输出文件：" << out_file << endl;
  cout << "视频帧数：" << video_count << endl;
  cout << "音频帧数：" << audio_count << endl;
  cout << "总时长：" << total_sec << endl;
  return 0;
}
